<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            height: 100%;
            margin: 0;
        }
    </style>
</head>

<body>
    <div id="alert1" style="white-space:pre-wrap;"></div>
    <br />
    <div id="alert2" style="white-space:pre-wrap;"></div>
    <canvas id="canvas1" style="position:absolute;left:0;top:0;"></canvas>

    <script>
        const alert1 = document.getElementById('alert1');
        const alert2 = document.getElementById('alert2');
        const canvas1 = document.getElementById('canvas1');
        const ctx = canvas1.getContext('2d');

        const keys = getOtherKeys(); // 获取其它窗口的storage keys
        const key = keys.length == 0 ? 1 : keys.at(-1) + 1; // 自增最大的key序号，定义自己窗口storage key
        const color = ['red', 'blue', 'green'][key % 3]; // 获取圆颜色

        // 窗口关闭时删除自己窗口storage
        window.onunload = function () {
            localStorage.removeItem(key);
        }

        function getOtherKeys() {
            const keys = [];
            for (let i = 0; i < localStorage.length; i++) {
                const k = Number(localStorage.key(i));
                !isNaN(k) && keys.push(k);
            }
            return keys.sort((a, b) => a - b);
        }

        function draw() {
            const { clientWidth, clientHeight } = document.body; // 获取body高宽
            const { screenX, screenY } = window; // 获取浏览器相对屏幕坐标
            const barHeight = window.outerHeight - window.innerHeight; // 获取浏览器body顶部地址栏高度

            // 记录log
            alert1.textContent = JSON.stringify({ key, clientWidth, clientHeight, screenX, screenY, barHeight }, '', 2);

            // 设置canvas为整个body高宽，铺满body
            canvas1.width = clientWidth;
            canvas1.height = clientHeight;

            // 获取自己的圆心坐标，为body中心
            const x = clientWidth / 2;
            const y = clientHeight / 2;

            // 画自己的圆
            ctx.fillStyle = color;
            ctx.beginPath();
            ctx.arc(x, y, 15, 0, Math.PI * 2);
            ctx.fill();

            // 记录自己的position
            const position = {
                top: y + barHeight + screenY, // 相对屏幕坐标
                left: x + screenX,
                color: color, // 自己的颜色
            };
            // 获取其它窗口position，并遍历
            getOtherKeys().forEach(k => {
                const position2 = JSON.parse(localStorage.getItem(k)); // 获取其中一个窗口的圆心position
                const w = position2.left - position.left; // 获取相对自己圆心的横向间距
                const h = position2.top - position.top; // 获取相对自己圆心的纵向间距

                // 在自己的canvas上画出该圆
                ctx.fillStyle = position2.color;
                ctx.beginPath();
                ctx.arc(x + w, y + h, 15, 0, Math.PI * 2);
                ctx.fill();

                // 画连接线
                ctx.strokeStyle = "black";
                ctx.beginPath();
                ctx.moveTo(x, y);
                ctx.lineTo(x + w, y + h);
                ctx.stroke();
            })

            // 更新自己窗口的position
            localStorage.setItem(key, JSON.stringify(position));

            // 记录log
            alert2.textContent = JSON.stringify(localStorage, '', 2);

            window.requestAnimationFrame(draw);
        }
        window.requestAnimationFrame(draw);

    </script>
</body>

</html>